#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@File    langxin.py
@IDE     ：PyCharm
@Author  ：gwj
@Date    ：2025/3/25 
@use    ：
'''
import json
import random
import sys
import traceback
from lxml import etree
from datetime import datetime, timedelta
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.base import MIMEBase
from email.encoders import encode_base64
import openpyxl
import pandas as pd
import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import time
import os
import requests
import fnmatch
import re
import logging
from mail import send_email
from headers import UserAgent
from chaojiying import Chaojiying_Client
from date_utils import *
from params import *
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains


'''
NDSD	Ndsd@1234	茶园新区紫微星超级充电站
NDSD	Ndsd@1234	直港充电站
NDSD	Ndsd@1234	人和园充电站
NDSD	Ndsd@1234	小马爱冲华龙充电站
SZXP	Ndsdtcl@01	充充有电荷叶榕充电站
SZXP	Ndsdtcl@01	宝鸭新能源直流充电站
SZXP	Ndsdtcl@01	坪地壹号超充汽车充电站
SZXP	Ndsdtcl@01	力刻冲快充站
SZXP	Ndsdtcl@01	联合壹号羽毛球馆充电站
'''
proj_name = '朗新能源'
zname = ['NDSD','SZXP']  # 登陆账号
zpwd = ['Ndsd@1234','Ndsdtcl@01']  # 登陆密码
plant_name_NDSD = ['茶园新区紫微星超级充电站','直港充电站','人和园充电站','小马爱冲华龙充电站']  # 电站名称
plant_name_SZXP = ['充充有电荷叶榕充电站','宝鸭新能源直流充电站','坪地壹号超充汽车充电站','力刻冲快充站','联合壹号羽毛球馆充电站']  # 电站名称
# 配置日志记录,使用绝对路径，防止脚本运行时，路径变化

logging.basicConfig(
    level=logging.INFO,  # 设置日志级别
    format='%(asctime)s - %(levelname)s - %(message)s',  # 设置日志格式
    datefmt='%Y-%m-%d %H:%M:%S',  # 设置日期时间格式
    handlers=[
        logging.FileHandler(r'D:/TCL/2025/PythonFile/log/' + proj_name + '_' +  today_yyyymmdd_str + '.log', mode='a'),  # 将日志保存到本地文件，mode='a'  ：表示以追加模式打开文件，避免每次运行脚本时覆盖之前的日志
        logging.StreamHandler()  # 同时将日志输出到控制台
    ]
)
post_url = stored_plant_post_url #'http://10.0.125.43:8150/gf/postEnergyStorageData'
#dowload__path = dowload__path #r'C:\Users\xby_ganweijian\Downloads' 
langxin_url = 'https://energy.bangdao-tech.com/login'

static_date_str = yesterday_yyyymmdd_str


#跑历史数在这里改开始--结束日期！！！！！！！！！！！
start_date = yesterday_yyyymmdd_str  #如果要跑历史数，需要修改为历史数的日期，格式为yyyyMMdd
end_date = yesterday_yyyymmdd_str   #如果要跑历史数，需要修改为历史数的日期，格式为yyyyMMdd
#！！！！！！！！！！！！！！！！！！
'''
start_date = '20250401'  #如果要跑历史数，需要修改为历史数的日期，格式为yyyyMMdd
end_date = '20250418' 
'''
#返回一个日期列表，格式为yyyyMMdd
def generate_dates(start_date, end_date):

    # 将字符串日期转换为 datetime 对象
    start = datetime.strptime(start_date, "%Y%m%d")
    end = datetime.strptime(end_date, "%Y%m%d")
    
    # 确保开始日期小于或等于结束日期
    if start > end:
        raise ValueError("开始日期必须小于或等于结束日期")
    
    # 生成日期列表
    dates = []
    current = start
    while current <= end:
        dates.append(current.strftime("%Y%m%d"))  # 格式化为 YYYYMMDD
        current += timedelta(days=1)  # 增加一天
    
    return dates



#返回指定日期行的数据
def extract_row_data(html_content, date):
    # 解析HTML
    tree = etree.HTML(html_content)
    
    # 使用XPath提取指定日期行的数据
    # 调整XPath表达式，确保提取 <span> 标签内的文本
    xpath_expression = f'//tr[@data-row-key="{date}"]/td//text()'
    row_data = tree.xpath(xpath_expression)
    # 去除多余的空格
    row_data = [data.strip() for data in row_data if data.strip()]
    return row_data    

# 初始化超级鹰客户端
def init_chaojiying():
    chaojiying = Chaojiying_Client('tcljrtcljr', 'tcljr@*2019', '948754') # 用户中心>>软件ID 生成一个替换 96001
    return chaojiying

# 截取滑块缺口验证的图片
def get_captcha_images(browser):
    # 等待滑块缺口验证元素出现
    time.sleep(2)
    
    # 截取背景图
    browser.save_screenshot('screenshot.png')
    bg_img = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/div[2]/form/div/div[3]/div')
    bg_location = bg_img.location
    bg_size = bg_img.size
    left = bg_location['x']
    top = bg_location['y']
    right = left + bg_size['width']
    bottom = top + bg_size['height']
    img = Image.open('screenshot.png')
    img = img.crop((left, top, right, bottom))
    img.save('bg.png')
    return 'bg.png' 

# 使用超级鹰识别滑块缺口位置
def get_slider_position(bg_image_path, chaojiying):
    im = open(bg_image_path, 'rb').read()
    result = chaojiying.PostPic(im, 9902)  # 9902 是超级鹰的滑块缺口识别类型
    if result['err_no'] == 0:
        position = result['pic_str']
        logging.info(f"滑块缺口位置: {position}")
        return position
    else:
        logging.info(f"超级鹰识别失败:{result['err_str']}")
        return None

# 模拟滑动操作
def move_slider(browser, distance):

    slider = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/div[2]/form/div/div[3]/div/div[2]/div/div[2]/div/div')

    ActionChains(browser).click_and_hold(slider).perform()
    ActionChains(browser).move_by_offset(distance, 0).release().perform()
    logging.info("滑块移动完成")
# 检查验证结果
def check_verification(browser):
    try:
        # 等待验证结果出现
        result_element = WebDriverWait(browser, 5).until(#出现电站矩阵说明成功进入
            EC.presence_of_element_located((By.XPATH, '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[2]/ul/li[2]/div/span'))
        )
        result_text = result_element.text
        logging.info("验证结果:", result_text)
        if "验证通过" in result_text:
            return True
        elif "验证失败" in result_text or "再来一次" in result_text:
            return False
        else:
            return None
    except TimeoutException:
        logging.info("验证结果未找到，可能需要重试")
        return None

#自动登录
def get_driver(plant_name_i,zname,zpwd,static_yyyy_mm_dd_str,static_yyyy_mm_str):
    options = webdriver.ChromeOptions()
    options.add_argument(f"user-agent={random.choice(UserAgent)}")
    # 关键参数配置
    options.add_argument("--disable-blink-features=AutomationControlled")  # 禁用Blink的自动化控制特征
    options.add_argument("--disable-infobars")  # 禁用信息栏
    options.add_argument("--disable-dev-shm-usage")  # 避免内存不足问题
    options.add_argument("--no-sandbox")  # 非沙箱模式（Linux服务器可能需要）
    options.add_argument("--disable-gpu")  # 禁用GPU加速（旧版系统可能需要）

    # 禁用自动化扩展（关键！）
    options.add_experimental_option("excludeSwitches", ["enable-automation"])  # 隐藏顶部的"Chrome正在受自动化测试控制"
    options.add_experimental_option("useAutomationExtension", False)  # 禁用自动化扩展
    # 禁用密码保存提示
    prefs = {
        "credentials_enable_service": False,
        "profile.password_manager_enabled": False
    }
    options.add_experimental_option("prefs", prefs)
    # 启动浏览器
    browser = webdriver.Chrome(options=options)
    # 覆盖navigator.webdriver属性（Chrome 79+ 必须使用CDP）
    browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        "source": """
            Object.defineProperty(navigator, 'webdriver', {
                get: () => undefined
            });
        """
    })
    # 可选：删除Selenium的全局变量（部分网站检测window.navigator.chrome）
    browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
        "source": """
            delete window.navigator.__proto__.chrome;
        """
    })
    browser.get(url=langxin_url)
    browser.maximize_window()  # 设置浏览器大小为全屏 --隐藏窗口不可使用
    browser.implicitly_wait(10)
    #点击账号密码登录
    browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/div[2]/form/div/div[1]/div[2]/div/span/input').send_keys(zname)
    browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/div[2]/form/div/div[2]/div[2]/div/span/span/input').send_keys(zpwd)
    time.sleep(2)
    #点击登录按钮
    login_xpath = '//*[@id="popContainer"]/div/div[1]/div/div[2]/form/button'
    browser.find_element(By.XPATH, login_xpath).click()
    time.sleep(2)

    
    # 初始化超级鹰客户端
    chaojiying = init_chaojiying()

    # 尝试次数
    max_attempts = 3
    attempts = 0

    while attempts < max_attempts:
        # 截取滑块缺口验证的图片
        bg_image_path = get_captcha_images(browser)

        # 使用超级鹰识别滑块缺口位置
        position = get_slider_position(bg_image_path, chaojiying)
        if position is None:
            logging.info("超级鹰识别失败，跳过本次尝试")
            attempts += 1
            continue

        # 解析坐标
        try:
            # 修正解析逻辑
            parts = position.split('|')
            x1, y1 = map(int, parts[0].split(','))
            x2, y2 = map(int, parts[1].split(','))
            distance = abs(x2 - x1)
            logging.info(f"滑块缺口位置: {distance}")
        except Exception as e:
            logging.error("解析坐标失败:", e)
            attempts += 1
            continue

        # 模拟滑动操作
        move_slider(browser, distance)
        time.sleep(10)

        # 检查验证结果
        try:
            confirm_res = browser.find_elements(By.XPATH, '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[2]/div/div')
            logging.info(f"找到 '数据中心' 按钮的数量：{len(confirm_res)}")
            # 等待“确定”按钮出现 
            if float(len(confirm_res)) == 1:
                logging.info("验证通过，继续登录")
                break
            else:
                logging.info("验证失败，尝试重新验证")
                attempts += 1
                time.sleep(2)  # 等待2秒后重试
                
        except Exception as e:
            logging.error(f"程序运行时出现错误: {e}")
            break     

    if attempts == max_attempts:
        logging.info(f"达到最大验证失败次数{max_attempts}，退出程序")
    else:
        logging.info(f"登录{zname}_{plant_name_i}成功！")
    # 等待一段时间，观察登录结果
    time.sleep(2)



    
   ###################进入网站，开始获取数据###################
   #循环执行获取电站信息
    '''
    plant_num = len(plant_name_NDSD)
    #循环执行获取电站信息
    for i in range(plant_num):
    
    #测试数据
    i=0
    '''
    ######################第一个窗口：电站矩阵(没有用到日期参数)################
    try:          
        #点击监控中心
        jkzx_xpath = '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[2]/div/div'
        browser.find_element(By.XPATH, jkzx_xpath).click()
        logging.info(f"点击监控中心")
        time.sleep(2)
        #点击电站矩阵
        dzjz_xpath = '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[2]/ul/li[2]/div'
        browser.find_element(By.XPATH, dzjz_xpath).click()
        logging.info(f"点击电站矩阵")
        time.sleep(2)

    
        #输入电站名称
        zcmc_xpath = '//*[@id="popContainer"]/div/div[1]/form/div/div[2]/div/div[2]/div/span/span/input'
        zcmc_xpath_len =len(browser.find_elements(By.XPATH, zcmc_xpath))
        #判断是否有匹配的电站名称，如果没有，刷新页面，重新输入
        if zcmc_xpath_len == 1:
            logging.info(f"正常进入页面")
        else:
            logging.info(f"未找到匹配的元素，刷新页面")
            browser.refresh()
            logging.info("刷新当前页面")
            time.sleep(5)
        browser.find_element(By.XPATH, zcmc_xpath).send_keys(plant_name_i)
        time.sleep(2)





        #点击查询
        cx_xpath = '//*[@id="popContainer"]/div/div[1]/form/div/div[4]/button[2]'
        browser.find_element(By.XPATH, cx_xpath).click()
        logging.info(f"点击查询，查询电站：{plant_name_i}")
        time.sleep(2)
        #点击查询出的电站
        cj_xpath = '//*[@id="popContainer"]/div/div[2]/div/div/div[1]/div/div'
        browser.find_element(By.XPATH, cj_xpath).click()
        time.sleep(2)

        #获取总收益、总放电电量、总充电电量的值
    
        # 等待“总收益”标签出现
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.XPATH, '//div[contains(text(), "总收益")]/following-sibling::div/div'))
        )
        
        # 获取“总收益”的值
        total_profit_element = browser.find_element(By.XPATH, '//div[contains(text(), "总收益")]/following-sibling::div/div')
        total_profit_text = total_profit_element.text
        # 将“万元”转换为“元”
        total_earnings = float(re.findall(r'\d+\.\d+', total_profit_text)[0]) * 10000
        logging.info(f"总收益（元）: {total_earnings}")
        time.sleep(2)
        # 获取“总放电电量”的值
        total_profit_element = browser.find_element(By.XPATH, '//div[contains(text(), "总放电电量")]/following-sibling::div/div')
        total_profit_text = total_profit_element.text
        # 将“兆瓦时”转换为“千瓦时”
        etot_f = float(re.findall(r'\d+\.\d+', total_profit_text)[0]) * 1000
        logging.info(f"总放电电量（KWH）: {etot_f}")
        time.sleep(2)
        # 获取“总充电电量”的值
        total_profit_element = browser.find_element(By.XPATH, '//div[contains(text(), "总充电电量")]/following-sibling::div/div')
        total_profit_text = total_profit_element.text
        # 将“兆瓦时”转换为“千瓦时”
        etot_c = float(re.findall(r'\d+\.\d+', total_profit_text)[0]) * 1000
        logging.info(f"总充电电量（KWH）: {etot_c}")
        time.sleep(2)
    except Exception as e:
        logging.error(f"程序运行_电站矩阵_时出现错误: {e}")



    ######################第二个窗口：计费账单窗口（日维度用到static_yyyy_mm_dd_str，月维度格式化成target_month_chinese（如：三月））#############
    try:
        #点击数据中心
        sjzx_xpath = '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[3]/div/div'
        browser.find_element(By.XPATH, sjzx_xpath).click()
        logging.info(f"点击数据中心")
        time.sleep(2)
        #点击计费账单
        jfzd_xpath = '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[3]/ul/li[1]'
        browser.find_element(By.XPATH, jfzd_xpath).click()
        logging.info(f"点击计费账单")

    
        # 等待筛选框出现
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.XPATH, '//div[@placeholder="请选择电站"]'))
        )
        
        # 点击筛选框，激活下拉菜单
        select_box = browser.find_element(By.XPATH, '//div[@placeholder="请选择电站"]')
        select_box.click()
        logging.info("点击筛选框，激活下拉菜单")
        
        # 等待输入框出现
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.XPATH, '//input[@aria-label="filter select"]'))
        )
        
        # 输入筛选值
        search_input = browser.find_element(By.XPATH, '//input[@aria-label="filter select"]')
        search_input.send_keys(plant_name_i)
        search_input.send_keys(Keys.ENTER)  # 按下回车键进行筛选
        logging.info(f"输入筛选值：{plant_name_i}")
        # 等待筛选结果出现
        time.sleep(2)  # 等待筛选结果加载完成
        
        # 选择匹配的选项
        option_xpath = f'//span[@title="{plant_name_i}"]'
        option_element = browser.find_element(By.XPATH, option_xpath)
        option_element.click()
        logging.info(f"筛选完成，已选择 {plant_name_i}")


        #筛选日期
        # 点击日期筛选框前，处理月账单的筛选格式
        
        # 把static_yyyy_mm_dd_str转换成日期类型
        static_date_date = datetime.strptime(static_yyyy_mm_dd_str, "%Y-%m-%d")
        # 计算目标月份（选择上个月）
        if static_date_date.month == 1:
            target_date = static_date_date.replace(year=static_date_date.year - 1, month=12)
        else:
            target_date = static_date_date.replace(month=static_date_date.month - 1)

                    
        # 英文月份到中文月份的映射
        month_mapping = {
            "January": "一月",
            "February": "二月",
            "March": "三月",
            "April": "四月",
            "May": "五月",
            "June": "六月",
            "July": "七月",
            "August": "八月",
            "September": "九月",
            "October": "十月",
            "November": "十一月",
            "December": "十二月"
        }

        # 获取目标月份的中文名称
        target_month_chinese = month_mapping[target_date.strftime('%B')]
        logging.info(f"目标月份的中文名称:, {target_month_chinese}")

        target_month = target_date.strftime('%Y-%m')  # 格式化为 YYYY-MM
        logging.info(f"目标月份:, {target_month}")

        # 等待页面加载完成
        # 等待日期选择器输入框出现
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.XPATH, '//input[@placeholder="请选择日期"]'))
        )
        
        # 点击日期选择器输入框，打开日期选择器
        date_input = browser.find_element(By.XPATH, '//input[@placeholder="请选择日期"]')
        date_input.click()
        
        # 等待月份选择面板加载完成
        WebDriverWait(browser, 10).until(
            EC.presence_of_element_located((By.XPATH, '//table[@class="ant-calendar-month-panel-table"]'))
        )
        

        # 定位到目标月份的元素
        target_month_element = browser.find_element(By.XPATH, f'//a[text()="{target_month_chinese}"]')
        
        # 点击目标月份以选中它
        target_month_element.click()
        logging.info(f"已成功选中 '{target_month_chinese}'")

        #点击搜素
        search_button = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/form/div/div[4]/button[1]')
        search_button.click()
        logging.info("点击搜索按钮")
        time.sleep(5)  # 等待搜索结果加载完成

        #获取页面源代码
        html_content = browser.find_element(By.XPATH, '//*[@id="tableExcel"]/tbody').get_attribute('outerHTML')
        # 解析 HTML
        tree = etree.HTML(html_content)
        # 使用 XPath 定位并提取值
        month_earnings = tree.xpath("//td[@class='share-content'][1]/text()")[0]
        if not month_earnings:
            month_earnings = ['0']
        # 打印结果
        logging.info(f"月收益:, {month_earnings}")
        #点击账单类型筛选器
        zdlx_xpath = '//*[@id="popContainer"]/div/div[1]/div/form/div/div[2]/div/div[2]/div/span/div[1]/div/div'
        browser.find_element(By.XPATH, zdlx_xpath).click()
        logging.info(f"点击账单类型筛选器")
        time.sleep(2)

        #点击日账单
        rq_xpath = '//*[@id="popContainer"]/div/div[1]/div/form/div/div[2]/div/div[2]/div/span/div[2]/div/div/div/ul/li[1]'
        browser.find_element(By.XPATH, rq_xpath).click()
        logging.info(f"点击日账单")
        time.sleep(2)
        #点击日期筛选器
        date_xpath = '//*[@id="popContainer"]/div/div[1]/div/form/div/div[3]/div/div[2]/div/span/span/div[1]/input'
        browser.find_element(By.XPATH, date_xpath).click()
        logging.info(f"点击日期筛选器")
        date_input = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/form/div/div[3]/div/div[2]/div/span/span/div[2]/div/div/div/div/div[1]/div/input')
        date_input.send_keys(static_yyyy_mm_dd_str)
        logging.info(f"输入日期：{static_yyyy_mm_dd_str}")
        #点击搜素
        search_button = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div[1]/div/form/div/div[4]/button[1]')
        search_button.click()
        logging.info("点击搜索按钮")
        time.sleep(5)  # 等待搜索结果加载完成
        #获取页面源代码
        html_content = browser.find_element(By.XPATH, '//*[@id="tableExcel"]/tbody').get_attribute('outerHTML')
        # 解析 HTML
        tree = etree.HTML(html_content)
        # 使用 XPath 定位并提取值
        day_earnings = tree.xpath("//td[@class='share-content'][1]/text()")[0]
        if not day_earnings:
            day_earnings = ['0']
        # 打印结果
        logging.info(f"日收益: {day_earnings}")
    except Exception as e:
        logging.error(f"程序运行_计费账单窗口_时出现错误: {e}")



    #####第三个窗口：储能电量统计报表#############################
    try:
        #点击储能电量统计报表
        dltj_xpath = '//*[@id="popContainer"]/section/section/aside/div/div[1]/ul[2]/li[3]/ul/li[3]/div'
        browser.find_element(By.XPATH, dltj_xpath).click()
        logging.info(f"点击储能电量统计报表")
        time.sleep(2)
        #点击所属电站
        xuanz_ssdz = '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[1]/div/div[2]/div/span/div/div/span'
        browser.find_element(By.XPATH, xuanz_ssdz).click()
        logging.info(f"选中所属电站")
        time.sleep(2)
        #清空默认值内容
        delete_input = '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[1]/div/div[2]/div/span/div/div/span/span/span[1]'
        browser.find_element(By.XPATH, delete_input).click()
        logging.info(f"清除默认值内容")
        time.sleep(1)
        #输入电站名称
        ssdz_input = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[1]/div/div[2]/div/span/div/div/span/span/ul/li/span/input')
        ssdz_input.send_keys(plant_name_i)
        time.sleep(2)
        logging.info(f"输入电站名称：{plant_name_i}")

        # 选择匹配的选项//*[@id="rc-tree-select-list_11"]/ul/li/ul/li/ul/li/span[3]/span
        option_xpath = f'//span[@title="{plant_name_i}"]'
        option_element = browser.find_element(By.XPATH, option_xpath)
        option_element.click()
        print(f"筛选完成，已选择 {plant_name_i}")



        #循环获取日月年的数据
        # 初始化一个空列表
        result_list = []
        for j in range(3):

            if j == 0:
                star_date_str = static_yyyy_mm_dd_str
                end_date_str = static_yyyy_mm_dd_str
            elif j == 1:
                #获取static_yyyy_mm_str当月月初1号的值
                star_date_str = static_yyyy_mm_str + '-01'
                end_date_str = static_yyyy_mm_dd_str
            else:
                #获取static_yyyy_mm_str当年年初1号的值，使用static_yyyy_mm_str来计算
                star_date_str = static_yyyy_mm_str.split('-')[0] + '-01-01'
                end_date_str = static_yyyy_mm_dd_str

            #点击日期筛选器-统计周期
            date_xpath = '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[2]/div/div[2]/div/span/span/span/input[1]'
            browser.find_element(By.XPATH, date_xpath).click()
            time.sleep(1)
            logging.info("点击统计周期")


            # 定位开始日期输入框并输入日期                         
            start_date_input = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[2]/div/div[2]/div/span/span/div/div/div/div/div/div[1]/div[1]/div[1]/div/input')
            start_date_input.click()  # 点击输入框激活日期选择器
            time.sleep(2)
            #start_date_input.clear()  # 清空输入框
            start_date_input.send_keys(Keys.CONTROL + 'a')  # 全选
            start_date_input.send_keys(Keys.BACKSPACE)     # 删除
            time.sleep(2)
            start_date_input.send_keys(star_date_str)
            time.sleep(2)

            #start_date_input.send_keys(Keys.ENTER)  # 按回车确认
            #time.sleep(2)
            logging.info(f"输入开始日期：{star_date_str}")
            
            # 定位结束日期输入框并输入日期                       
            end_date_input = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[2]/div/div[2]/div/span/span/div/div/div/div/div/div[1]/div[2]/div[1]/div/input')
            end_date_input.click()  # 点击输入框激活日期选择器
            time.sleep(1)
            #end_date_input.clear()  # 清空输入框
            end_date_input.send_keys(Keys.CONTROL + 'a')  # 全选
            end_date_input.send_keys(Keys.BACKSPACE)     # 删除
            time.sleep(1)
            end_date_input.send_keys(end_date_str)
            
            end_date_input.send_keys(Keys.ENTER)  # 按回车确认
            time.sleep(2)
            logging.info(f"输入开始日期：{star_date_str}，输入结束日期：{end_date_str}")
            
            #点击汇总时间
            zhsj_xpath = '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[3]/div/div[2]/div/span/div/div/div'
            browser.find_element(By.XPATH, zhsj_xpath).click()
            logging.info("点击汇总时间")
            time.sleep(2)
            #点击日、月、年     
            r_xpath = f'//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[3]/div/div[2]/div/span/div[2]/div/div/div/ul/li[{j+1}]'
            browser.find_element(By.XPATH, r_xpath).click()
            time.sleep(2)
            #点击搜素
            search_button = browser.find_element(By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[1]/form/div/div[5]/button[2]')
            search_button.click()
            logging.info("点击搜索按钮")
            time.sleep(2)



            # 显式等待元素加载完成并且包含文本
            element = WebDriverWait(browser, 10).until(
                EC.text_to_be_present_in_element((By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[2]/div[2]/div[1]/div[2]/div[1]/div[2]'), '')
            )
            # 直接使用 Selenium 提取 c_z_list 和 f_z_list
            c_z_elements = browser.find_elements(By.XPATH, '//*[@class="vxe-table--body-wrapper body--wrapper"]//table//tr//td[4]//span')
            c_z_list = [element.text for element in c_z_elements]
            logging.info(f"充电量列表：{c_z_list}")
            f_z_elements = browser.find_elements(By.XPATH, '//*[@class="vxe-table--body-wrapper body--wrapper"]//table//tr//td[5]//span')
            f_z_list = [element.text for element in f_z_elements]
            logging.info(f"放电量列表：{f_z_list}")


            '''
            # 显式等待元素加载完成
            element = WebDriverWait(browser, 10).until(
                EC.presence_of_element_located((By.XPATH, '//*[@id="popContainer"]/div/div/div/div/div[2]/div[2]/div[1]/div[2]/div[1]/div[2]'))
            )
            #获取页面源代码
            html_content = element.get_attribute('outerHTML')
            time.sleep(2)
            # 解析 HTML
            tree = etree.HTML(html_content)
            time.sleep(3)
            # 使用 XPath 定位并提取值
            c_z_list = tree.xpath('//*[@class="vxe-table--body-wrapper body--wrapper"]//table//tr//td[4]//span/text()')
            f_z_list = tree.xpath('//*[@class="vxe-table--body-wrapper body--wrapper"]//table//tr//td[5]//span/text()')
            time.sleep(3)
            '''
            #有一些电站的数据是没有，考虑把空值改为0
            if not c_z_list:
                c_z_list = ['0']
            if not f_z_list:
                f_z_list = ['0']
            if c_z_list and f_z_list and j == 0: 
                #c_z_list[0]
                c_z_data = c_z_list[0]
                f_z_data = f_z_list[0]
                # 打印结果
                logging.info(f"日充电量:{c_z_data},日放电量：{f_z_data}")
            elif c_z_list and f_z_list and j == 1:
                c_z_data = c_z_list[0]
                f_z_data = f_z_list[0]
                # 打印结果
                logging.info(f"月充电量:{c_z_data},月放电量：{f_z_data}")
            elif c_z_list and f_z_list and j == 2:
                c_z_data = c_z_list[0]
                f_z_data = f_z_list[0]
                # 打印结果
                logging.info(f"年充电量:{c_z_data},年放电量：{f_z_data}")
            else:
                logging.error("未找到日充电量或日放电量信息")

            #同时提取eday_c_z、eday_f_z、emonth_c_z、emonth_f_z、eyear_c_z、eyear_f_z的值，放到列表中
            # 将两个数据依次添加到列表中
            result_list.append(c_z_data)
            result_list.append(f_z_data)
            #j自增
            j += 1
            #将result_list的值赋值给result_list
            result_list = result_list
        logging.info(f"日月年充放电量分别为{result_list}") #调取方式：c_z_data[0]
        


            
    except Exception as e:
        logging.error(f"程序运行_储能电量统计报表窗口_时出现错误: {e}")

        

    return browser,total_earnings,etot_f,etot_c,month_earnings,day_earnings,result_list,plant_name_i


def data_send(retries,static_date_str,static_yyyy_mm_dd_str,static_yyyy_mm_str):
    #启动浏览器
    # 在原代码中，`get_driver` 函数返回的是一个元组 (browser, total_power_consumption, month_power_consumption)，
    # 因此需要从元组中提取出 `browser` 对象，然后再调用 `quit` 方法关闭浏览器。
    #如果账号为retries，则循环len(plant_name_NDSD)次
    #获取plant_name_NDSD的长度
    if retries == 0:
        plant_name = plant_name_NDSD
        plant_num = len(plant_name_NDSD)
    else:
        plant_name = plant_name_SZXP
        plant_num = len(plant_name_SZXP)
    #循环执行获取电站信息
    for i in range(plant_num):
        try:
            plant_name_i = plant_name[i]
            # 调用 get_driver 函数，获取浏览器对象和数据，如果有报错，立马退出浏览器
            browser,total_earnings,etot_f,etot_c,month_earnings,day_earnings,result_list,plant_name_i = get_driver(plant_name_i,zname[retries],zpwd[retries],static_yyyy_mm_dd_str,static_yyyy_mm_str)
            browser.quit()
            time.sleep(3)
        except Exception as e:
            logging.error(f"浏览器获取数据时出现错误: {e}")
            


        #发送数据！！！！！！！！！！！！！！！！！！！！！！！！
        try:
            if total_earnings is not None:
                logging.info("日月年数据获取成功")
                # 数据处理
                data =  {"plant_name": plant_name_i,
                    "stored_energy_url": langxin_url,
                    "update_time": today_yyyymmdd_str,
                    "static_date": static_date_str,
                    "eday_c_z": str(result_list[0]),#日充电量
                    "eday_c_j": "",
                    "eday_c_f": "",
                    "eday_c_p": "",
                    "eday_c_g": "",
                    "eday_c_sg":"",
                    "eday_f_z": str(result_list[1]),#日放电量
                    "eday_f_j": "",
                    "eday_f_f": "",
                    "eday_f_p": "",
                    "eday_f_g": "",
                    "eday_f_sg": "",
                    "etot_c": str(etot_c),#总充电量
                    "etot_f": str(etot_f),#总放电量
                    "eyear_c": str(result_list[4]),
                    "eyear_f": str(result_list[5]),
                    "emonth_c": str(result_list[2]),
                    "emonth_f": str(result_list[3]),
                    "day_earnings": str(day_earnings),
                    "month_earnings": str(month_earnings),
                    "year_earnings": "",
                    "total_earnings": str(total_earnings) }
                # 将数据转换为JSON格式
                json_data = json.dumps(data)
                response = requests.post(url=post_url, data=json_data)
                logging.info(response.text)
                logging.info(response.status_code)
                success_flag = response.json().get('code') == 0
                send_email(proj_name, plant_name_i, static_date_str, success_flag)
        except Exception as e:
            logging.error(f"获取数据时出现错误: {e}")
            # 构建错误信息
            exc_type, exc_value, exc_tb = sys.exc_info()
            tb_list = traceback.format_exception(exc_type, exc_value, exc_tb)
            error_msg = f"""
                        发生未处理异常：
                        异常类型：{exc_type.__name__}
                        错误信息：{str(exc_value)}
                        异常位置：{tb_list[-2].strip()}
                        完整堆栈：
                        {''.join(tb_list)}
                        """
            send_email(proj_name, plant_name_i, static_date_str, is_success=False, error=error_msg) 



def main(static_date_str):      #默认 static_date_str = yesterday_yyyymmdd_str




    #把'20250330'转换为日期格式'2025-03-30'
    static_date_date = datetime.strptime(static_date_str, "%Y%m%d")
    static_yyyy_mm_dd_str = static_date_date.strftime("%Y-%m-%d")
    static_yyyy_mm_str = static_date_date.strftime("%Y-%m")

    zhanghaoshu = 2  # 登陆账号数，利用data_send方法循环执行浏览器登录不同账号
    retries = 0
    while retries < zhanghaoshu:
        #获取开始日期和结束日期,如果开始日期和结束日期一致，则只跑这一天
        if start_date == end_date:
            max_retries = 3  # 最大重试次数
            rerun = 0
            while rerun <= max_retries:
                try:
                    static_date_str = start_date
                    logging.info(f"开始日期和结束日期一致，跑{static_date_str}数")
                    data_send(retries,static_date_str,static_yyyy_mm_dd_str,static_yyyy_mm_str)
                    logging.info("跑T-1数据成功，结束")
                    rerun += 4  # 如果没有错误，跳出重试循环
                #出现错误再重跑一次，尽量避免可能网络延迟导致xpath获取失败的情况
                except Exception as e:
                    rerun += 1
                    if rerun <= max_retries:
                        logging.error(f"程序运行时出现错误: {e}，正在进行第 {rerun} 次重试...")
                    else:
                        logging.info("已达到最大重试次数，停止重试。")
                        logging.error(f"程序运行时出现错误: {e}")
        #如果开始日期和结束日期不一致，则跑历史数
        else:
            max_retries = 3  # 最大重试次数
            rerun = 0
            while rerun <= max_retries:
                try:
                    logging.info("开始日期和结束日期不一致，开始循环跑历史数")
                    #循环
                    dates = generate_dates(start_date, end_date)
                    for static_date_str in dates:
                        static_date_date = datetime.strptime(static_date_str, "%Y%m%d")
                        static_yyyy_mm_dd_str = static_date_date.strftime("%Y-%m-%d")
                        static_yyyy_mm_str = static_date_date.strftime("%Y-%m")
                        logging.info(f"跑{static_date_str}这一天的数据")
                        data_send(retries,static_date_str,static_yyyy_mm_dd_str,static_yyyy_mm_str)
                        logging.info(f"跑{static_date_str}数据成功，继续跑下一天数据")
                    #break  # 如果没有错误，跳出重试循环
                    logging.info("跑历史数据成功，结束")
                        #出现错误再重跑一次，尽量避免可能网络延迟导致xpath获取失败的情况
                    rerun += 4
                except Exception as e:
                    rerun += 1
                    if rerun <= max_retries:
                        logging.error(f"程序运行时出现错误: {e}，正在进行第 {rerun} 次重试...")
                    else:
                        logging.info("已达到最大重试次数，停止重试。")
                        logging.error(f"程序运行时出现错误: {e}")
        retries += 1
    


    
if __name__ == '__main__':
    main(static_date_str)